﻿//#define XML_DEBUG

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace KMouse
{
    class Param
    {
        //常量
        public const double _VersionGit = 30.1;	//Git版本号
       
        static public Dictionary<string, object> dict_bak;
        static public Dictionary<string, object> dict = new Dictionary<string, object>();

        static public string path_ini_file = ".\\KMouseIni.xml";   //初始化窗体时会复制成exe的名字

        static public void SaveIniParam()
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.AppendChild(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", null));

            XmlElement xmlRoot;
            XmlElement xmlChild;
            XmlElement xmlElementInner;
            XmlAttribute xmlAttribute;

            xmlRoot = xmlDocument.CreateElement("Root");
            xmlDocument.AppendChild(xmlRoot);

            //Child-COM
            xmlChild = xmlDocument.CreateElement("Child-COM");                          //创建一个child(子节点)
                xmlElementInner = xmlDocument.CreateElement("Element-COM");             //创建一个Element(元素)

                    xmlAttribute = xmlDocument.CreateAttribute("COM_IS_OPEN");          //创建一个Attribute(键)
                    xmlAttribute.Value = dict["COM_IS_OPEN"].ToString();                //修改对应键的值
                    xmlElementInner.Attributes.SetNamedItem(xmlAttribute);              //将键值装到元素里
            
                    xmlAttribute = xmlDocument.CreateAttribute("COM_SELECT");
                    xmlAttribute.Value = dict["COM_SELECT"].ToString();
                    xmlElementInner.Attributes.SetNamedItem(xmlAttribute);

                    xmlAttribute = xmlDocument.CreateAttribute("COM_BAUDRATE");
                    xmlAttribute.Value = dict["COM_BAUDRATE"].ToString();
                    xmlElementInner.Attributes.SetNamedItem(xmlAttribute);

                xmlChild.AppendChild(xmlElementInner);                                  //将元素装到子节点里
            xmlRoot.AppendChild(xmlChild);                                              //将Child加入到Root里

            //Child-Config
            xmlChild = xmlDocument.CreateElement("Child-Config");

                xmlAttribute = xmlDocument.CreateAttribute("EKEY_STRING");
                xmlAttribute.Value = dict["EKEY_STRING"].ToString();
                xmlElementInner = xmlDocument.CreateElement("Element-EKEY_STRING");
                xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                xmlChild.AppendChild(xmlElementInner);

                xmlAttribute = xmlDocument.CreateAttribute("FUNC_OP");
                xmlAttribute.Value = dict["FUNC_OP"].ToString();
                xmlElementInner = xmlDocument.CreateElement("Element-FUNC_OP");
                xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                xmlChild.AppendChild(xmlElementInner);

                xmlAttribute = xmlDocument.CreateAttribute("CMDLIST_CYCLE");
                xmlAttribute.Value = dict["CMDLIST_CYCLE"].ToString();
                xmlElementInner = xmlDocument.CreateElement("Element-CMDLIST_CYCLE");
                xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                xmlChild.AppendChild(xmlElementInner);

                xmlAttribute = xmlDocument.CreateAttribute("CMDLIST_INTERVAL");
                xmlAttribute.Value = dict["CMDLIST_INTERVAL"].ToString();
                xmlElementInner = xmlDocument.CreateElement("Element-CMDLIST_INTERVAL");
                xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                xmlChild.AppendChild(xmlElementInner);

                xmlAttribute = xmlDocument.CreateAttribute("BAT_PATH");
                xmlAttribute.Value = dict["BAT_PATH"].ToString();
                xmlElementInner = xmlDocument.CreateElement("Element-BAT_PATH");
                xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                xmlChild.AppendChild(xmlElementInner);

                xmlAttribute = xmlDocument.CreateAttribute("AUTHORIZE_KEY");
                xmlAttribute.Value = dict["AUTHORIZE_KEY"].ToString();
                xmlElementInner = xmlDocument.CreateElement("Element-AUTHORIZE_KEY");
                xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                xmlChild.AppendChild(xmlElementInner);

            xmlRoot.AppendChild(xmlChild);

            System.IO.StringReader sr;
            int attr_tag = 0;
            string cmd_list;

            //Child-Cmdlist-Command
            xmlChild = xmlDocument.CreateElement("Child-Cmdlist-Command");
                cmd_list = dict["CMDLIST_COMMAND"].ToString();
                sr = new System.IO.StringReader(cmd_list);
                attr_tag = 0;
                while(true)
                {
                    string line = sr.ReadLine();
                    if(line == null)
                    {
                        break;
                    }

                    xmlAttribute = xmlDocument.CreateAttribute("NO." + attr_tag.ToString());
                    xmlAttribute.Value = line;
                    xmlElementInner = xmlDocument.CreateElement("Element-COMMAND." + attr_tag.ToString());
                    xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                    xmlChild.AppendChild(xmlElementInner);
                    attr_tag++;
                }
                sr.Close();
            xmlRoot.AppendChild(xmlChild);

            //Child-Cmdlist-Keyword
            xmlChild = xmlDocument.CreateElement("Child-Cmdlist-Keyword");
                cmd_list = dict["CMDLIST_KEYWORD"].ToString();
                sr = new System.IO.StringReader(cmd_list);
                attr_tag = 0;
                while(true)
                {
                    string line = sr.ReadLine();
                    if(line == null)
                    {
                        break;
                    }

                    xmlAttribute = xmlDocument.CreateAttribute("NO." + attr_tag.ToString());
                    xmlAttribute.Value = line;
                    xmlElementInner = xmlDocument.CreateElement("Element-KEYWORD." + attr_tag.ToString());
                    xmlElementInner.Attributes.SetNamedItem(xmlAttribute);
                    xmlChild.AppendChild(xmlElementInner);
                    attr_tag++;
                }
                sr.Close();
            xmlRoot.AppendChild(xmlChild);

            //保存XML文件
            xmlDocument.Save(path_ini_file);
        }

        static private void InitParamDirectory()    //创建字典，并填写默认值
        {
            dict.Add("COM_IS_OPEN", false);
            dict.Add("COM_SELECT", -1);
            dict.Add("COM_BAUDRATE", -1);

            dict.Add("EKEY_STRING", "Hello world");
            dict.Add("FUNC_OP", 0);
            dict.Add("CMDLIST_CYCLE", 0);
            dict.Add("CMDLIST_INTERVAL", 5);
            dict.Add("BAT_PATH", "");
            dict.Add("AUTHORIZE_KEY", "0");
            
            dict.Add("CMDLIST_COMMAND", "Identify()");
            dict.Add("CMDLIST_KEYWORD", "");
        }

        static private string GetXmlVal(XmlDocument xml_doc, string root, string child, string element, string attribute)
        {
#if XML_DEBUG
            Dbg.WriteLine("Xml:%s root:% child:% element:% attribute:%", xml_doc, root, child, element, attribute);
#endif
            XmlNode xml_root = xml_doc.SelectSingleNode(root);
            XmlNode xml_child = xml_root.SelectSingleNode(child);
            XmlNode xml_element = xml_child.SelectSingleNode(element);

            return xml_element.Attributes.GetNamedItem(attribute).Value;
        }


        static private int GetXmlValCnt(XmlDocument xml_doc, string root, string child)
        {
            //    XmlDocument xmlDocument = new XmlDocument();
            //    xmlDocument.Load("KMouseIni.xml");

            //    XmlNode xmlRoot = xmlDocument.SelectSingleNode("Root");

            //    foreach(XmlNode child in xmlRoot)
            //    {
            //        Console.WriteLine("Child: " + child.Name);
            //        foreach(XmlNode element in child)
            //        {
            //            Console.WriteLine("\t Element: " + element.Name);

            //            XmlNode Node = child.SelectSingleNode(element.Name);
            //            foreach(XmlAttribute value in Node.Attributes)
            //            {
            //                Console.WriteLine("\t\t Attribute Name: " + value.Name + " Value: " + value.Value);
            //            }
            //        }
            //    }
#if XML_DEBUG
            Dbg.WriteLine("Xml:%s root:% child:%", xml_doc, root, child);
#endif
            XmlNode xml_root = xml_doc.SelectSingleNode(root);
            XmlNode xml_child = xml_root.SelectSingleNode(child);

            int cnt = 0;
            foreach(XmlNode note in xml_child)
            {
#if XML_DEBUG
                Dbg.WriteLine("\t\t Element[%]: %", cnt, note.Name);
#endif
                cnt++;
            }

            return cnt;
        }


        static public bool ChkDictIsEqual(Dictionary<string, object> dict1, Dictionary<string, object> dict2)
        {
            string[] key1_strline = new string[128];
            string[] val1_strline = new string[128];
            int dict1_cnt = 0;

            string[] key2_strline = new string[128];
            string[] val2_strline = new string[128];
            int dict2_cnt = 0;

            //遍历字典
            foreach(KeyValuePair<string, object> kvp in dict1)
            {
                //Dbg.WriteLine("@key1:% val1:%\n", kvp.Key, kvp.Value);
                key1_strline[dict1_cnt] = kvp.Key.ToString();
                val1_strline[dict1_cnt] = kvp.Value.ToString();
                dict1_cnt++;
            }

            foreach(KeyValuePair<string, object> kvp in dict2)
            {
                //Dbg.WriteLine("@key2:% val2:%\n", kvp.Key, kvp.Value);
                key2_strline[dict2_cnt] = kvp.Key.ToString();
                val2_strline[dict2_cnt] = kvp.Value.ToString();
                dict2_cnt++;
            }
            if(dict1_cnt != dict2_cnt)
            {
                return false;
            }

            for(int i = 0; i < dict1_cnt; i++)
            {
                if(key1_strline[i] != key2_strline[i])
                {
                    Dbg.WriteLine("key1:% key2:%\n", key1_strline[i], key2_strline[i]);
                    return false;
                }

                if(val1_strline[i] != val2_strline[i])
                {
                    Dbg.WriteLine("[%]len:%,% val1:% val2:%\n", i,
                        val1_strline[i].Length, 
                        val2_strline[i].Length, 
                        val1_strline[i], 
                        val2_strline[i]);
                    return false;
                }
            }

            return true;
        }

        static public void LoadIniParameter()
        {
            Dbg.WriteLine("Load param Start...");

            InitParamDirectory();

        tag_open:
            if(File.Exists(path_ini_file) == false) //第一次创建ini文件，填写默认值
            {
                Dbg.WriteLine("Create ini xml file!");
                SaveIniParam();

                goto tag_open;
            }

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(path_ini_file);

            //Child-COM
            dict["COM_IS_OPEN"] = GetXmlVal(xmlDocument, "Root", "Child-COM", "Element-COM", "COM_IS_OPEN") == "True" ? true : false;
            dict["COM_SELECT"] = int.Parse(GetXmlVal(xmlDocument, "Root", "Child-COM", "Element-COM", "COM_SELECT"));
            dict["COM_BAUDRATE"] = int.Parse(GetXmlVal(xmlDocument, "Root", "Child-COM", "Element-COM", "COM_BAUDRATE"));
            
            //Child-Config
            dict["EKEY_STRING"] = GetXmlVal(xmlDocument, "Root", "Child-Config", "Element-EKEY_STRING", "EKEY_STRING");
            dict["FUNC_OP"] = int.Parse(GetXmlVal(xmlDocument, "Root", "Child-Config", "Element-FUNC_OP", "FUNC_OP"));
            dict["CMDLIST_CYCLE"] = int.Parse(GetXmlVal(xmlDocument, "Root", "Child-Config", "Element-CMDLIST_CYCLE", "CMDLIST_CYCLE"));
            dict["CMDLIST_INTERVAL"] = int.Parse(GetXmlVal(xmlDocument, "Root", "Child-Config", "Element-CMDLIST_INTERVAL", "CMDLIST_INTERVAL"));
            dict["BAT_PATH"] = GetXmlVal(xmlDocument, "Root", "Child-Config", "Element-BAT_PATH", "BAT_PATH");
            dict["AUTHORIZE_KEY"] = GetXmlVal(xmlDocument, "Root", "Child-Config", "Element-AUTHORIZE_KEY", "AUTHORIZE_KEY");

            string cmdlist_tmp_str;
            int total;
            //Child-Cmdlist-Command
            total = GetXmlValCnt(xmlDocument, "Root", "Child-Cmdlist-Command");
            cmdlist_tmp_str = "";
            for(int cnt = 0; cnt < total; cnt++)
            {
                cmdlist_tmp_str += GetXmlVal(xmlDocument, "Root", "Child-Cmdlist-Command", "Element-COMMAND." + cnt, "NO." + cnt);
                if(cnt + 1 != total)
                {
                    cmdlist_tmp_str += "\n";      //结尾不能有换行，否则解释命令时会出错
                }
            }
            dict["CMDLIST_COMMAND"] = cmdlist_tmp_str;

            //Child-Cmdlist-Keyword
            total = GetXmlValCnt(xmlDocument, "Root", "Child-Cmdlist-Keyword");
            cmdlist_tmp_str = "";            
            for(int cnt = 0; cnt < total; cnt++)
            {
                cmdlist_tmp_str += GetXmlVal(xmlDocument, "Root", "Child-Cmdlist-Keyword", "Element-KEYWORD." + cnt, "NO." + cnt);
                if(cnt + 1 != total)
                {
                    //注意，richtextbox会自己把\r\n变成\n，导致长度前后不一，所以这里同意用\n
                    cmdlist_tmp_str += "\n";      //结尾不能有换行，否则解释命令时会出错
                }
            }
            dict["CMDLIST_KEYWORD"] = cmdlist_tmp_str;

            dict_bak = new Dictionary<string, object>(dict);//直接用等号指示复制地址，要想把值复制过去需要用该方法！

            Dbg.WriteLine("Load param done!");
        }

        public static bool GetBoolFromParameter(int parameter, int shiftbit)
        {
            bool res;
            
            if((parameter & (1 << shiftbit)) != 0)
            {
                res = true;
            }
            else
            {
                res = false;
            }

            //Console.WriteLine("Get:{0:X} {1:X} res:{2:X}", parameter, shiftbit, res);

            return res;
        }

        public static void SetBoolToParameter(ref int parameter, bool val, int shiftbit)
        {
            int res;

            if (val == true)
            {
                parameter |= 1 << shiftbit;
            }
            else
            {
                parameter &= ~(1 << shiftbit);
            }

            res = parameter;
        }
    }
}
